home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / math / ast53src.zip / XCHARTS0.C < prev    next >
C/C++ Source or Header  |  1996-09-29  |  32KB  |  922 lines

  1. /*
  2. ** Astrolog (Version 5.30) File: xcharts0.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1996 by Walter D. Pullen
  6. ** (Astara@msn.com, http://www.magitech.com/~cruiser1/astrolog.htm).
  7. ** Permission is granted to freely use and distribute these routines
  8. ** provided one doesn't sell, restrict, or profit from them in any way.
  9. ** Modification is allowed provided these notices remain with any
  10. ** altered or edited versions of the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 9/22/1996.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. #ifdef GRAPH
  42. /*
  43. ******************************************************************************
  44. ** Subchart Graphics Routines.
  45. ******************************************************************************
  46. */
  47.  
  48. /* Given a string, draw it on the screen using the given color. The       */
  49. /* position of the text is based the saved positions of where we drew the */
  50. /* text the last time the routine was called, being either directly below */
  51. /* in the same column or in the same row just to the right. This is used  */
  52. /* by the sidebar drawing routine to print a list of text on the chart.   */
  53.  
  54. int DrawPrint(sz, m, n)
  55. char *sz;
  56. int m, n;
  57. {
  58.   static int x0, x, y;
  59.  
  60.   if (sz == NULL) {    /* Null string means just initialize position. */
  61.     x0 = x = m; y = n;
  62.     return y;
  63.   }
  64.   if (y >= gs.yWin-1)  /* Don't draw if we've scrolled off the chart bottom. */
  65.     return y;
  66.   DrawColor(m);
  67.   DrawSz(sz, x, y, dtLeft | dtBottom);
  68.  
  69.   /* If the second parameter is TRUE, we stay on the same line, otherwise */
  70.   /* when FALSE we go to the next line at the original column setting.    */
  71.  
  72.   if (n)
  73.     x += CchSz(sz)*xFont*gi.nScaleT;
  74.   else {
  75.     x = x0;
  76.     n = y;
  77.     y += yFont*gi.nScaleT;
  78.   }
  79.   return y;
  80. }
  81.  
  82.  
  83. /* Print text showing the chart information and house and planet positions */
  84. /* of a chart in a "sidebar" to the right of the chart in question. This   */
  85. /* is always done for the -v and -w graphic wheel charts unless the -v0    */
  86. /* switch flag is also set, in which case none of the stuff here is done.  */
  87.  
  88. void DrawInfo()
  89. {
  90.   char sz[cchSzDef];
  91.   ET et;
  92.   CI ciT;
  93.   int i, y, a, s;
  94.  
  95. #ifdef INTERPRET
  96.   int tot, abo, lef;
  97.  
  98.   /* Hack: Just for fun, if interpretation is active (which normally has  */
  99.   /* no effect whatsoever on graphics) we'll decorate the chart a little. */
  100.  
  101.   if (us.fInterpret) {
  102.     if (us.nScreenWidth & 1) {
  103.  
  104.       /* If screenwidth value is odd, draw a moire pattern in each corner. */
  105.  
  106.       abo = gs.yWin/(us.nScreenWidth/10);
  107.       lef = gs.xWin/(us.nScreenWidth/10);
  108.       for (y = 0; y <= 1; y++)
  109.         for (i = 0; i <= 1; i++)
  110.           for (s = 0; s <= 1; s++)
  111.             for (a = 1; a < (s ? lef : abo)*2; a++) {
  112.               DrawColor(a & 1 ? gi.kiGray : gi.kiOff);
  113.               DrawLine(i ? gs.xWin-1-lef : lef, y ? gs.yWin-1-abo : abo,
  114.                 s ? (i ? gs.xWin-1-a : a) : i*(gs.xWin-1),
  115.                 s ? y*(gs.yWin-1) : (y ? gs.yWin-1-a : a));
  116.             }
  117.     } else {
  118.  
  119.       /* If screenwidth is even, draw spider web lines in each corner. */
  120.  
  121.       DrawColor(gi.kiGray);
  122.       tot = us.nScreenWidth*3/20;
  123.       abo = gs.yWin/4;
  124.       lef = gs.xWin/4;
  125.       for (y = 0; y <= 1; y++)
  126.         for (i = 0; i <= 1; i++)
  127.           for (a = 1; a < tot; a++)
  128.             DrawLine(i*(gs.xWin-1), y ? (gs.yWin-1-a*abo/tot) : a*abo/tot,
  129.               i ? gs.xWin-1-lef+a*lef/tot : lef-a*lef/tot, y*(gs.yWin-1));
  130.     }
  131.   }
  132. #endif
  133.   if (!gs.fText || us.fVelocity)    /* Don't draw sidebar if */
  134.     return;                         /* -v0 flag is set.      */
  135.  
  136.   a = us.fAnsiChar;
  137.   us.fAnsiChar = (!gs.fFont || (!gs.fMeta && !gs.fPS)) << 1;
  138.   if (us.nRel == rcTransit) {
  139.     ciT = ciMain; ciMain = ciTwin;
  140.   }
  141.   DrawColor(gi.kiLite);
  142.   if (gs.fBorder)
  143.     DrawLine(gs.xWin-1, 0, gs.xWin-1, gs.yWin-1);
  144.   gs.xWin += xSideT;
  145.   DrawPrint(NULL, gs.xWin-xSideT+xFontT-gi.nScaleT, yFont*7/5*gi.nScaleT);
  146.  
  147.   /* Print chart header and setting information. */
  148.  
  149.   sprintf(sz, "%s %s", szAppName, szVersionCore);
  150.   DrawPrint(sz, gi.kiOn, fFalse);
  151.   if (*ciMain.nam)
  152.     DrawPrint(ciMain.nam, gi.kiLite, fFalse);
  153.   if (fNoTimeOrSpace)
  154.     sprintf(sz, "No time or space.");
  155.   else if (us.nRel == rcComposite)
  156.     sprintf(sz, "Composite chart.");
  157.   else {
  158.     sprintf(sz, "%c%c%c %s", chDay3(DayOfWeek(Mon, Day, Yea)),
  159.       SzDate(Mon, Day, Yea, fTrue));
  160.     DrawPrint(sz, gi.kiLite, fFalse);
  161.     DrawPrint(SzTim(Tim), gi.kiLite, fTrue);
  162.     sprintf(sz, " (%cT %s GMT)", ChDst(Dst), SzZone(Zon));
  163.   }
  164.   DrawPrint(sz, gi.kiLite, fFalse);
  165.   if (*ciMain.loc)
  166.     DrawPrint(ciMain.loc, gi.kiLite, fFalse);
  167.   if (Mon != -1)
  168.     DrawPrint(SzLocation(Lon, Lat), gi.kiLite, fFalse);
  169.   sprintf(sz, "%s houses.", szSystem[us.nHouseSystem]);
  170.   DrawPrint(sz, gi.kiLite, fFalse);
  171.   sprintf(sz, "%s, %s.", us.fSidereal ? "Sidereal" : "Tropical",
  172.     us.objCenter == oSun ? "Heliocentric" :
  173.     (us.objCenter == oEar ? "Geocentric" : szObjName[us.objCenter]));
  174.   DrawPrint(sz, gi.kiLite, fFalse);
  175.   sprintf(sz, "Julian Day = %11.4f", JulianDayFromTime(is.T));
  176.   DrawPrint(sz, gi.kiLite, fFalse);
  177.  
  178.   /* Print house cusp positions. */
  179.  
  180.   DrawPrint("", gi.kiLite, fFalse);
  181.   for (i = 1; i <= cSign; i++) {
  182.     sprintf(sz, "%2d%s house: ", i, szSuffix[i]);
  183.     y = DrawPrint(sz, kSignB(i), fTrue);
  184.     if (!is.fSeconds && (gs.nScale == 100 ||
  185.       !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) {
  186.       s = gi.nScale;
  187.       gi.nScale = gi.nScaleT;
  188.       DrawSign(SFromZ(chouse[i]), gs.xWin-12*gi.nScaleT,
  189.         y-(yFont/2-1)*gi.nScaleT);
  190.       gi.nScale = s;
  191.     }
  192.     DrawPrint(SzZodiac(chouse[i]), kSignB(SFromZ(chouse[i])), fFalse);
  193.   }
  194.  
  195.   /* Print planet positions. */
  196.  
  197.   DrawPrint("", gi.kiLite, fFalse);
  198.   for (i = 0; i <= oNorm; i++) if (FProper2(i) && !FCusp(i)) {
  199.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[i]);
  200.     DrawPrint(sz, kObjB[i], fTrue);
  201.     y = DrawPrint(SzZodiac(planet[i]), kSignB(SFromZ(planet[i])), fTrue);
  202.     if (!is.fSeconds && i < starLo && (gs.nScale == 100 ||
  203.       !gs.fFont || !gi.fFile || gs.fBitmap) && y < gs.yWin-1) {
  204.       s = gi.nScale;
  205.       gi.nScale = gi.nScaleT;
  206.       DrawObject(i, gs.xWin-12*gi.nScaleT, y-(yFont/2-1)*gi.nScaleT);
  207.       gi.nScale = s;
  208.     }
  209.     sprintf(sz, "%c ", ret[i] < 0.0 ? chRet : ' ');
  210.     s = FThing(i);
  211.     DrawPrint(sz, gi.kiOn, s);
  212.     if (s) {
  213.       is.fSeconds = fFalse;
  214.       DrawPrint(SzAltitude(planetalt[i]), gi.kiLite, fFalse);
  215.       is.fSeconds = us.fSeconds;
  216.     }
  217.   }
  218.  
  219.   /* Print star positions. */
  220.  
  221.   for (i = starLo; i <= starHi; i++) if (FProper(i)) {
  222.     s = oNorm+starname[i-oNorm];
  223.     sprintf(sz, is.fSeconds ? "%3.3s: " : "%4.4s: ", szObjName[s]);
  224.     DrawPrint(sz, kObjB[s], fTrue);
  225.     DrawPrint(SzZodiac(planet[s]), kSignB(SFromZ(planet[s])), fTrue);
  226.     DrawPrint("  ", gi.kiOn, fTrue);
  227.     DrawPrint(SzAltitude(planetalt[s]), gi.kiLite, fFalse);
  228.   }
  229.  
  230.   /* Print element table information. */
  231.  
  232.   DrawPrint("", gi.kiLite, fFalse);
  233.   CreateElemTable(&et);
  234.   sprintf(sz, "Fire: %d, Earth: %d,", et.coElem[eFir], et.coElem[eEar]);
  235.   DrawPrint(sz, gi.kiLite, fFalse);
  236.   sprintf(sz, "Air : %d, Water: %d", et.coElem[eAir], et.coElem[eWat]);
  237.   DrawPrint(sz, gi.kiLite, fFalse);
  238.   sprintf(sz, "Car: %d, Fix: %d, Mut: %d",
  239.     et.coMode[0], et.coMode[1], et.coMode[2]);
  240.   DrawPrint(sz, gi.kiLite, fFalse);
  241.   sprintf(sz, "Yang: %d, Yin: %d", et.coYang, et.coYin);
  242.   DrawPrint(sz, gi.kiLite, fFalse);
  243.   sprintf(sz, "M: %d, N: %d, A: %d, D: %d",
  244.     et.coMC, et.coIC, et.coAsc, et.coDes);
  245.   DrawPrint(sz, gi.kiLite, fFalse);
  246.   sprintf(sz, "Ang: %d, Suc: %d, Cad: %d",
  247.     et.coModeH[0], et.coModeH[1], et.coModeH[2]);
  248.   DrawPrint(sz, gi.kiLite, fFalse);
  249.   sprintf(sz, "Learn: %d, Share: %d", et.coLearn, et.coShare);
  250.   DrawPrint(sz, gi.kiLite, fFalse);
  251.   us.fAnsiChar = a;
  252.   if (us.nRel == rcTransit)
  253.     ciMain = ciT;
  254. }
  255.  
  256.  
  257. /* This is a subprocedure of XChartWheel() and XChartWheelRelation(). Draw  */
  258. /* the outer sign and house rings for a wheel chart at the specified zodiac */
  259. /* locations and at the given radius values.                                */
  260.  
  261. void DrawWheel(xsign, xhouse, cx, cy, unitx, unity, asc, r1, r2, r3, r4, r5)
  262. real *xsign, *xhouse;
  263. int cx, cy;
  264. real unitx, unity, asc, r1, r2, r3, r4, r5;
  265. {
  266.   int i;
  267.   real px, py, temp;
  268.  
  269.   /* Draw Ascendant/Descendant and Midheaven/Nadir lines across whole chart. */
  270.  
  271.   DrawColor(gi.kiLite);
  272.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sAri])),
  273.            cy+POINT1(unity, 0.99, PY(xhouse[sAri])),
  274.            cx+POINT1(unitx, 0.99, PX(xhouse[sLib])),
  275.            cy+POINT1(unity, 0.99, PY(xhouse[sLib])), !gs.fColor);
  276.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sCap])),
  277.            cy+POINT1(unity, 0.99, PY(xhouse[sCap])),
  278.            cx+POINT1(unitx, 0.99, PX(xhouse[sCan])),
  279.            cy+POINT1(unity, 0.99, PY(xhouse[sCan])), !gs.fColor);
  280.  
  281.   /* Draw small five or one degree increments around the zodiac sign ring. */
  282.  
  283.   for (i = 0; i < nDegMax; i++) {
  284.     temp = PZ(HousePlaceInX((real)i));
  285.     px = PX(temp); py = PY(temp);
  286.     DrawColor(i%5 ? gi.kiGray : gi.kiOn);
  287.     DrawDash(cx+POINT1(unitx, r3, px), cy+POINT1(unity, r3, py),
  288.       cx+POINT2(unitx, r4, px), cy+POINT2(unity, r4, py),
  289.       ((!gs.fColor || gs.fPS || gs.fMeta) && i%5)*2);
  290.   }
  291.  
  292.   /* Draw circles for the zodiac sign and house rings. */
  293.  
  294.   DrawColor(gi.kiOn);
  295.   DrawCircle(cx, cy, (int)(unitx*0.95+rRound), (int)(unity*0.95+rRound));
  296.   DrawCircle(cx, cy, (int)(unitx*r4+rRound), (int)(unity*r4+rRound));
  297.   DrawCircle(cx, cy, (int)(unitx*r3+rRound), (int)(unity*r3+rRound));
  298.   DrawCircle(cx, cy, (int)(unitx*r1+rRound), (int)(unity*r1+rRound));
  299.  
  300.   /* Draw the glyphs for the signs and houses themselves. */
  301.  
  302.   for (i = 1; i <= cSign; i++) {
  303.     temp = xsign[i];
  304.     DrawColor(gi.kiOn);
  305.     DrawLine(cx+POINT2(unitx, 0.95, PX(temp)),    /* Draw lines separating */
  306.       cy+POINT2(unity, 0.95, PY(temp)),           /* each sign and house   */
  307.       cx+POINT1(unitx, r4, PX(temp)),             /* from each other.      */
  308.       cy+POINT1(unity, r4, PY(temp)));
  309.     DrawLine(cx+POINT2(unitx, r3, PX(xhouse[i])),
  310.       cy+POINT2(unity, r3, PY(xhouse[i])),
  311.       cx+POINT1(unitx, r1, PX(xhouse[i])),
  312.       cy+POINT1(unity, r1, PY(xhouse[i])));
  313.     if (gs.fColor && i%3 != 1) {                             /* Lines from */
  314.       DrawColor(gi.kiGray);                                  /* each house */
  315.       DrawDash(cx, cy, cx+POINT2(unitx, r1, PX(xhouse[i])),  /* to center  */
  316.         cy+POINT2(unity, r1, PY(xhouse[i])), 1);             /* of wheel.  */
  317.     }
  318.     temp = Midpoint(temp, xsign[Mod12(i+1)]);
  319.     DrawColor(kSignB(i));
  320.     DrawSign(i, cx+POINT1(unitx, r5, PX(temp)),
  321.       cy+POINT1(unity, r5, PY(temp)));
  322.     temp = Midpoint(xhouse[i], xhouse[Mod12(i+1)]);
  323.     DrawHouse(i, cx+POINT1(unitx, r2, PX(temp)),
  324.       cy+POINT1(unity, r2, PY(temp)));
  325.   }
  326. }
  327.  
  328.  
  329. /* Another subprocedure of XChartWheel() and XChartWheelRelation(). Draw */
  330. /* a set of planets in a wheel chart, drawing each glyph and a line from */
  331. /* it to a dot indicating the planet's actual location.                  */
  332.  
  333. void DrawSymbolRing(symbol, xplanet, dir, cx, cy, unitx, unity, r1, r2, r3, r4)
  334. real *symbol, *xplanet, *dir;
  335. int cx, cy;
  336. real unitx, unity, r1, r2, r3, r4;
  337. {
  338.   int i;
  339.   real temp;
  340.  
  341.   for (i = cObj; i >= 0; i--) if (FProper(i)) {
  342.     if (gs.fLabel) {
  343.       temp = symbol[i];
  344.       DrawColor(dir[i] < 0.0 ? gi.kiGray : gi.kiOn);
  345.       DrawDash(cx+POINT1(unitx, r2, PX(xplanet[i])),
  346.         cy+POINT1(unity, r2, PY(xplanet[i])),
  347.         cx+POINT1(unitx, r3, PX(temp)),
  348.         cy+POINT1(unity, r3, PY(temp)),
  349.         (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  350.       DrawObject(i, cx+POINT1(unitx, r4, PX(temp)),
  351.         cy+POINT1(unity, r4, PY(temp)));
  352.     } else
  353.       DrawColor(kObjB[i]);
  354.     DrawPoint(cx+POINT1(unitx, r1, PX(xplanet[i])),
  355.       cy+POINT1(unity, r1, PY(xplanet[i])));
  356.   }
  357. }
  358.  
  359.  
  360. /*
  361. ******************************************************************************
  362. ** Map Chart Routines.
  363. ******************************************************************************
  364. */
  365.  
  366. /* Another stream reader, this one is used by the globe drawing routine: */
  367. /* for the next body of land/water, return its name (and color), its     */
  368. /* longitude and latitude, and a vector description of its outline.      */
  369.  
  370. bool FReadWorldData(nam, loc, lin)
  371. char FPTR **nam, FPTR **loc, FPTR **lin;
  372. {
  373.   static char FPTR **psz = (char FPTR **)szWorldData;
  374.   int i;
  375.  
  376.   *loc = *psz++;
  377.   *lin = *psz++;
  378.   *nam = *psz++;
  379.   if (*loc[0]) {
  380.     if (gs.fPrintMap && gi.fFile) {
  381.       i = **nam - '0';
  382.       AnsiColor(i ? kRainbowA[i] : kMainA[7]);
  383.       PrintSz(*nam+1); PrintL();
  384.     }
  385.     return fTrue;
  386.   }
  387.   psz = (char FPTR **)szWorldData;  /* Reset stream when no data left. */
  388.   return fFalse;
  389. }
  390.  
  391.  
  392. /* Given longitude and latitude values on a globe, return the window        */
  393. /* coordinates corresponding to them. In other words, project the globe     */
  394. /* onto the view plane, and return where our coordinates got projected to,  */
  395. /* as well as whether our location is hidden on the back side of the globe. */
  396.  
  397. bool FGlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg)
  398. real x1, y1;
  399. int *u, *v, cx, cy, rx, ry, deg;
  400. {
  401.   real j, siny1;
  402.  
  403.   /* Compute coordinates for a general globe invoked with -XG switch. */
  404.  
  405.   if (gi.nMode == gGlobe) {
  406.     x1 = Mod(x1+(real)deg);    /* Shift by current globe rotation value. */
  407.     if (gs.rTilt != 0.0) {
  408.       /* Do another coordinate shift if the globe's equator is tilted any. */
  409.       x1 = RFromD(x1); y1 = RFromD(rDegQuad-y1);
  410.       CoorXform(&x1, &y1, RFromD(gs.rTilt));
  411.       x1 = Mod(DFromR(x1)); y1 = rDegQuad-DFromR(y1);
  412.     }
  413.     *v = cy + (int)((real)ry*-RCosD(y1)-rRound);
  414.     *u = cx + (int)((real)rx*-RCosD(x1)*RSinD(y1)-rRound);
  415.     return x1 > rDegHalf;
  416.   }
  417.  
  418.   /* Compute coordinates for a polar globe invoked with -XP switch. */
  419.  
  420.   siny1 = RSinD(y1);
  421.   j = gs.fAlt ? rDegQuad+x1+deg : 270.0-x1-deg;
  422.   *v = cy + (int)(siny1*(real)ry*RSinD(j)-rRound);
  423.   *u = cx + (int)(siny1*(real)rx*RCosD(j)-rRound);
  424.   return gs.fAlt ? y1 < rDegQuad : y1 > rDegQuad;
  425. }
  426.  
  427.  
  428. /* Draw one "Ley line" on the world map, based coordinates given in terms of */
  429. /* longitude and vertical fractional distance from the center of the earth.  */
  430.  
  431. void DrawLeyLine(l1, f1, l2, f2)
  432. real l1, f1, l2, f2;
  433. {
  434.   l1 = Mod(l1); l2 = Mod(l2);
  435.  
  436.   /* Convert vertical fractional distance to a corresponding coordinate. */
  437.  
  438.   f1 = rDegQuad-RAsin(f1)/rPiHalf*rDegQuad;
  439.   f2 = rDegQuad-RAsin(f2)/rPiHalf*rDegQuad;
  440.   DrawWrap((int)(l1*(real)gi.nScale+rRound),
  441.            (int)(f1*(real)gi.nScale+rRound),
  442.            (int)(l2*(real)gi.nScale+rRound),
  443.            (int)(f2*(real)gi.nScale+rRound), 0, gs.xWin-1);
  444. }
  445.  
  446.  
  447. /* Draw the main set of planetary Ley lines on the map of the world. This */
  448. /* consists of drawing an icosahedron and then a dodecahedron lattice.    */
  449.  
  450. void DrawLeyLines(deg)
  451. int deg;
  452. {
  453.   real off = (real)deg, phi, h, h1, h2, r, i;
  454.  
  455.   phi = (RSqr(5.0)+1.0)/2.0;                   /* Icosahedron constants. */
  456.   h = 1.0/(phi*2.0-1.0);
  457.   DrawColor(kMainB[6]);
  458.   for (i = off; i < rDegMax+off; i += 72.0) {  /* Draw icosahedron edges. */
  459.     DrawLeyLine(i, h, i+72.0, h);
  460.     DrawLeyLine(i-36.0, -h, i+36.0, -h);
  461.     DrawLeyLine(i, h, i, 1.0);
  462.     DrawLeyLine(i+36.0, -h, i+36.0, -1.0);
  463.     DrawLeyLine(i, h, i+36.0, -h);
  464.     DrawLeyLine(i, h, i-36.0, -h);
  465.   }
  466.   r = 1.0/RSqr(3.0)/phi/RCos(RFromD(54.0));    /* Dodecahedron constants. */
  467.   h2 = RSqr(1.0-r*r); h1 = h2/(phi*2.0+1.0);
  468.   DrawColor(kMainB[4]);
  469.   for (i = off; i < rDegMax+off; i += 72.0) {  /* Draw docecahedron edges. */
  470.     DrawLeyLine(i-36.0, h2, i+36.0, h2);
  471.     DrawLeyLine(i, -h2, i+72.0, -h2);
  472.     DrawLeyLine(i+36.0, h2, i+36.0, h1);
  473.     DrawLeyLine(i, -h2, i, -h1);
  474.     DrawLeyLine(i+36.0, h1, i+72.0, -h1);
  475.     DrawLeyLine(i+36.0, h1, i, -h1);
  476.   }
  477. }
  478.  
  479.  
  480. /* This major routine draws all of Astrolog's map charts. This means       */
  481. /* either the world map or the constellations, in either rectangular or    */
  482. /* globe hemisphere form. The rectangular chart may also be done in a      */
  483. /* Mollewide projection, for six total combinations. We shift the chart by */
  484. /* specified rotational and tilt values, and may draw on the chart each    */
  485. /* planet at its zenith position on Earth or location in constellations.   */
  486.  
  487. void DrawMap(fSky, fGlobe, deg)
  488. bool fSky, fGlobe;
  489. int deg;
  490. {
  491.   char *nam, *loc, *lin, chCmd;
  492.   int X[objMax], Y[objMax], M[objMax], N[objMax],
  493.     cx = gs.xWin/2, cy = gs.yWin/2, rx, ry, lon, lat, unit = 12*gi.nScale,
  494.     x, y, xold, yold, m, n, u, v, i, j, k, l, nScl = gi.nScale;
  495.   bool fNext = fTrue, fCan;
  496.   real planet1[objMax], planet2[objMax], x1, y1, rT;
  497. #ifdef CONSTEL
  498.   char *pch;
  499.   bool fBlank;
  500.   int isz = 0, nC, xT, yT, xDelta, yDelta, xLo, xHi, yLo, yHi;
  501. #endif
  502.  
  503.   /* Set up some variables. */
  504.   rx = cx-1; ry = cy-1;
  505.   if (fGlobe)
  506.     fCan = (gs.rTilt == 0.0 && gi.nMode != gPolar);
  507.  
  508. #ifdef CONSTEL
  509.   /* Draw a dot grid for large rectangular constellation charts. */
  510.   if (fSky && !fGlobe && !gs.fMollewide && gi.nScale/gi.nScaleT > 2)
  511.     for (yT = 5; yT < nDegHalf; yT += 5)
  512.       for (xT = 5; xT <= nDegMax; xT += 5) {
  513.         DrawColor(xT % 15 == 0 && yT % 10 == 0 ? gi.kiOn : gi.kiGray);
  514.         x = xT+deg;
  515.         if (x > nDegMax)
  516.           x -= nDegMax;
  517.         DrawPoint(x*nScl, yT*nScl);
  518.       }
  519. #endif
  520.  
  521.   loop {
  522.  
  523.     /* Get the next chunk of data to process. Get the starting position, */
  524.     /* map it to the screen, and set the drawing color appropriately.    */
  525.  
  526.     if (fNext) {
  527.       fNext = fFalse;
  528.  
  529.       /* For constellations, get data for the next constellation shape. */
  530.  
  531.       if (fSky) {
  532. #ifdef CONSTEL
  533.         isz++;
  534.         if (isz > cCnstl)
  535.           break;
  536.         DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode != gWorldMap ||
  537.           !gs.fMollewide) ? kMainB[7] : kRainbowB[6]);
  538.         pch = (char *)szDrawConstel[isz];
  539.         lon = nDegMax -
  540.           (((pch[2]-'0')*10+(pch[3]-'0'))*15+(pch[4]-'0')*10+(pch[5]-'0'));
  541.         lat = 90-((pch[6] == '-' ? -1 : 1)*((pch[7]-'0')*10+(pch[8]-'0')));
  542.         pch += 9;
  543.         xLo = xHi = xT = xold = x = lon;
  544.         yLo = yHi = yT = yold = y = lat;
  545.         nC = 0;
  546.         if (fGlobe) {
  547.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  548.           k = l = fTrue;
  549.         } else {
  550.           xold += deg;
  551.           x += deg;
  552.         }
  553. #else
  554.         ;
  555. #endif
  556.  
  557.       /* For world maps, get data for the next coastline piece. */
  558.  
  559.       } else {
  560.         if (!FReadWorldData(&nam, &loc, &lin))
  561.           break;
  562.         i = nam[0]-'0';
  563.         DrawColor((!fGlobe && gi.nMode == gAstroGraph) ? gi.kiOn :
  564.           (gi.nMode == gGlobe && gs.fAlt) ? gi.kiGray :
  565.           (i ? kRainbowB[i] : kMainB[7]));
  566.         lon = (loc[0] == '+' ? 1 : -1)*
  567.           ((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
  568.         lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
  569.         if (fGlobe) {
  570.           x = 180-lon;
  571.           y = 90-lat;
  572.           FGlobeCalc((real)x, (real)y, &m, &n, cx, cy, rx, ry, deg);
  573.           k = l = fTrue;
  574.         } else {
  575.           xold = x = 181-lon+deg;
  576.           yold = y = 90-lat;
  577.         }
  578.       }
  579.     }
  580.  
  581.     /* Get the next unit from the string to draw on the screen as a line. */
  582.  
  583.     if (fSky) {
  584.  
  585.       /* For constellations we have a cache of how long we should keep    */
  586.       /* going in the previous direction, as say "u5" for up five should  */
  587.       /* move our pointer up five times without advancing string pointer. */
  588.  
  589. #ifdef CONSTEL
  590.       if (nC <= 0) {
  591.         if (!(chCmd = *pch)) {
  592.           fNext = fTrue;
  593.           if (gs.fText) {
  594.  
  595.             /* If we've reached the end of current constellation, compute */
  596.             /* the center location in it based on lower and upper bounds  */
  597.             /* we've maintained, and print the name of the constel there. */
  598.  
  599.             xT = xLo + (xHi - xLo)*(szDrawConstel[isz][0]-'1')/8;
  600.             yT = yLo + (yHi - yLo)*(szDrawConstel[isz][1]-'1')/8;
  601.             if (xT < 0)
  602.               xT += nDegMax;
  603.             else if (xT > nDegMax)
  604.               xT -= nDegMax;
  605.             if (fGlobe) {
  606.               if (FGlobeCalc((real)xT, (real)yT, &x, &y, cx, cy, rx, ry, deg))
  607.                 continue;
  608.             } else {
  609.               xT += deg;
  610.               if (xT > nDegMax)
  611.                 xT -= nDegMax;
  612.               if (gs.fMollewide)
  613.                 x = 180*nScl + NMultDiv(xT-180, NMollewide(yT-91), 180L);
  614.               else
  615.                 x = xT*nScl;
  616.               y = yT*nScl;
  617.             }
  618.             DrawColor(gs.fAlt && gi.nMode != gPolar && (gi.nMode !=
  619.               gWorldMap || !gs.fMollewide) ? gi.kiGray : kMainB[5]);
  620.             DrawSz(szCnstlAbbrev[isz], x, y, dtCent);
  621.           }
  622.           continue;
  623.         }
  624.         pch++;
  625.  
  626.         /* Get the next direction and distance from constellation string. */
  627.  
  628.         if (fBlank = (chCmd == 'b'))
  629.           chCmd = *pch++;
  630.         xDelta = yDelta = 0;
  631.         switch (chCmd) {
  632.         case 'u': yDelta = -1; break;    /* Up    */
  633.         case 'd': yDelta =  1; break;    /* Down  */
  634.         case 'l': xDelta = -1; break;    /* Left  */
  635.         case 'r': xDelta =  1; break;    /* Right */
  636.         case 'U': yDelta = -1; nC = (yT-1)%10+1;    break;  /* Up until    */
  637.         case 'D': yDelta =  1; nC = 10-yT%10;       break;  /* Down until  */
  638.         case 'L': xDelta = -1; nC = (xT+599)%15+1;  break;  /* Left until  */
  639.         case 'R': xDelta =  1; nC = 15-(xT+600)%15; break;  /* Right until */
  640.         default: PrintError("Bad draw.");             /* Shouldn't happen. */
  641.         }
  642.         if (chCmd >= 'a')
  643.           nC = NFromPch(&pch);    /* Figure out how far to draw. */
  644.       }
  645.       nC--;
  646.       xT += xDelta; x += xDelta;
  647.       yT += yDelta; y += yDelta;
  648.       if (fBlank) {
  649.         xold = x; yold = y;    /* We occasionally want to move the pointer */
  650.         l = fFalse;            /* without drawing the line on the screen.  */
  651.         continue;
  652.       }
  653.       if (xT < xLo)         /* Maintain our bounding rectangle for this */
  654.         xLo = xT;           /* constellation if we crossed over it any. */
  655.       else if (xT > xHi)
  656.         xHi = xT;
  657.       if (yT < yLo)
  658.         yLo = yT;
  659.       else if (yT > yHi)
  660.         yHi = yT;
  661. #else
  662.       ;
  663. #endif
  664.  
  665.     } else {
  666.  
  667.       /* Get the next unit from the much simpler world map strings. */
  668.  
  669.       if (!(chCmd = *lin)) {
  670.         fNext = fTrue;
  671.         continue;
  672.       }
  673.       lin++;
  674.  
  675.       /* Each unit is exactly one character in the coastline string. */
  676.  
  677.       if (chCmd == 'L' || chCmd == 'H' || chCmd == 'G')
  678.         x--;
  679.       else if (chCmd == 'R' || chCmd == 'E' || chCmd == 'F')
  680.         x++;
  681.       if (chCmd == 'U' || chCmd == 'H' || chCmd == 'E')
  682.         y--;
  683.       else if (chCmd == 'D' || chCmd == 'G' || chCmd == 'F')
  684.         y++;
  685.     }
  686.  
  687.     /* Transform map coordinates to screen coordinates and draw a line. */
  688.  
  689.     while (x >= nDegMax)    /* Take care of coordinate wrap around. */
  690.       x -= nDegMax;
  691.     while (x < 0)
  692.       x += nDegMax;
  693.     if (abs(x-xold) > nDegHalf)
  694.       xold = x;
  695.  
  696.     if (fGlobe) {
  697.  
  698.       /* For globes, we have to go do a complicated transformation, and not */
  699.       /* draw when we're hidden on the back side of the sphere. We're smart */
  700.       /* and try to only do the slow stuff when we know we'll be visible.   */
  701.  
  702.       if (fCan) {
  703.         k = x+deg;
  704.         if (k >= nDegMax)
  705.           k -= nDegMax;
  706.         k = (k <= 180);
  707.       }
  708.       if (k && !FGlobeCalc((real)x, (real)y, &u, &v, cx, cy, rx, ry, deg)) {
  709.         if (l)
  710.           DrawLine(m, n, u, v);
  711.         m = u; n = v;
  712.         l = fTrue;
  713.       } else
  714.         l = fFalse;
  715.     } else {
  716.  
  717.       /* Rectangular maps are much simpler, with screen coordinates      */
  718.       /* proportional to internal coords. For the Mollewide projection   */
  719.       /* we have to apply a factor to the horizontal positioning though. */
  720.  
  721.       if (gs.fMollewide && gi.nMode != gAstroGraph)
  722.         DrawLine(180*nScl + NMultDiv(xold-180,
  723.           NMollewide(yold-91), 180L), (yold-1)*nScl,
  724.           180*nScl + NMultDiv(x-180, NMollewide(y-91), 180L), (y-1)*nScl);
  725.       else
  726.         DrawLine(xold*nScl, (yold-1)*nScl, x*nScl, (y-1)*nScl);
  727.       xold = x; yold = y;
  728.     }
  729.   }
  730.  
  731.   /* Draw the outline of the map, either a circle around globes or a */
  732.   /* Mollewide type ellipse for that type of rectangular chart.      */
  733.  
  734.   DrawColor(gi.kiOn);
  735.   if (!fGlobe) {
  736.     if (gs.fMollewide && gi.nMode != gAstroGraph)
  737.       if (!gs.fAlt)
  738.         for (j = -1; j <= 1; j += 2)
  739.           for (xold = 0, y = 89; y >= 0; y--, xold = x)
  740.             for (x = NMollewide(y), i = -1; i <= 1; i += 2)
  741.               {
  742.               DrawLine(180*nScl + i*xold - (i==1), (90+j*(y+1))*nScl - (j==1),
  743.                 180*nScl + i*x - (i==1), (90+j*y)*nScl - (j==1));
  744.               }
  745.   } else
  746.     DrawEllipse(0, 0, gs.xWin-1, gs.yWin-1);
  747.  
  748.   /* Now, if we are in an appropriate bonus chart mode, draw each planet at */
  749.   /* its zenith or visible location on the globe or map, if not hidden.     */
  750.  
  751.   if (!gs.fAlt || (gi.nMode != gGlobe &&
  752.     (!fSky || gi.nMode != gWorldMap || gs.fMollewide)))
  753.     return;
  754.   rT = gs.fConstel ? rDegHalf - (fGlobe ? 0.0 : (real)deg) : Lon;
  755.   if (rT < 0.0)
  756.     rT += rDegMax;
  757.   for (i = 1; i <= cObj; i++) {
  758.     planet1[i] = RFromD(Tropical(planet[i]));
  759.     planet2[i] = RFromD(planetalt[i]);
  760.     EclToEqu(&planet1[i], &planet2[i]);    /* Calculate zenith long. & lat. */
  761.   }
  762.  
  763.   /* Compute screen coordinates of each object, if it's even visible. */
  764.  
  765.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  766.     if (fSky)
  767.       x1 = planet1[i];
  768.     else
  769.       x1 = planet1[oMC]-planet1[i];
  770.     if (x1 < 0.0)
  771.       x1 += 2.0*rPi;
  772.     if (x1 > rPi)
  773.       x1 -= 2.0*rPi;
  774.     x1 = Mod(rDegHalf-rT-DFromR(x1));
  775.     y1 = rDegQuad-DFromR(planet2[i]);
  776.     if (fGlobe) {
  777.       X[i] = FGlobeCalc(x1, y1, &u, &v, cx, cy, rx, ry, deg) ? -1000 : u;
  778.       Y[i] = v;
  779.     } else {
  780.       X[i] = (int)(x1 * (real)nScl);
  781.       Y[i] = (int)(y1 * (real)nScl);
  782.     }
  783.     M[i] = X[i]; N[i] = Y[i]+unit/2;
  784.   }
  785.  
  786.   /* Now that we have the coordinates of each object, figure out where to   */
  787.   /* draw the glyphs. Again we try not to draw glyphs on top of each other. */
  788.  
  789.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  790.     k = l = gs.xWin+gs.yWin;
  791.  
  792.     /* For each planet, we draw the glyph either right over or right under */
  793.     /* the actual zenith location point. So, find out the closest distance */
  794.     /* of any other planet assuming we place ours at both possibilities.   */
  795.  
  796.     for (j = 1; j < i; j++) if (FProper(j)) {
  797.       k = Min(k, abs(M[i]-M[j])+abs(N[i]-N[j]));
  798.       l = Min(l, abs(M[i]-M[j])+abs(N[i]-unit-N[j]));
  799.     }
  800.  
  801.     /* Normally, we put the glyph right below the actual point. If however  */
  802.     /* another planet is close enough to have their glyphs overlap, and the */
  803.     /* above location is better, then we'll draw the glyph above instead.   */
  804.  
  805.     if (k < unit || l < unit)
  806.       if (k < l)
  807.         N[i] -= unit;
  808.   }
  809.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i))      /* Draw the */
  810.     DrawObject(i, M[i], N[i]);                                  /* glyphs.  */
  811.   for (i = cObj; i >= 1; i--) if (X[i] >= 0 && FProper(i)) {
  812.     DrawColor(kObjB[i]);
  813.     DrawSpot(X[i], Y[i]);
  814.   }
  815. }
  816.  
  817.  
  818. /* Create a chart in the window based on the current graphics chart mode. */
  819. /* This is the main dispatch routine for all of the program's graphics.   */
  820.  
  821. void DrawChartX()
  822. {
  823.   char sz[cchSzDef];
  824.   int i;
  825.   bool fT;
  826.  
  827.   gi.nScale = gs.nScale/100;
  828.  
  829.   if (gs.fBitmap || gs.fMeta)
  830.     PrintNotice("Creating graphics chart in memory.");
  831.   DrawClearScreen();
  832. #ifdef CONSTEL
  833.   fT = gs.fConstel;
  834. #else
  835.   fT = fFalse;
  836. #endif
  837.   switch (gi.nMode) {
  838.   case gWheel:
  839.   case gHouse:
  840.     if (us.nRel > rcDual)
  841.       XChartWheel();
  842.     else if (us.nRel == rcTriWheel || us.nRel == rcQuadWheel)
  843.       XChartWheelThreeFour();
  844.     else
  845.       XChartWheelRelation();
  846.     break;
  847.   case gGrid:
  848.     if (us.nRel > rcDual)
  849.       XChartGrid();
  850.     else
  851.       XChartGridRelation();
  852.     break;
  853.   case gHorizon:
  854.     if (us.fPrimeVert)
  855.       XChartHorizonSky();
  856.     else
  857.       XChartHorizon();
  858.     break;
  859.   case gOrbit:
  860.     XChartOrbit();
  861.     break;
  862.   case gSector:
  863.     XChartSector();
  864.     break;
  865.   case gDisposit:
  866.     XChartDispositor();
  867.     break;
  868.   case gAstroGraph:
  869.     DrawMap(fFalse, fFalse, gs.nRot);  /* First draw map of world.           */
  870.     XChartAstroGraph();                /* Then draw astro-graph lines on it. */
  871.     break;
  872.   case gCalendar:
  873.     XChartCalendar();
  874.     break;
  875.   case gEphemeris:
  876.     XChartEphemeris();
  877.     break;
  878.   case gWorldMap:
  879.     DrawMap(fT, fFalse, gs.nRot);           /* First draw map of world. */
  880.     if (!fT && gs.fAlt && !gs.fMollewide)   /* Then maybe Ley lines.    */
  881.       DrawLeyLines(gs.nRot);
  882.     break;
  883.   case gGlobe:
  884.   case gPolar:
  885.     DrawMap(fT, fTrue, gs.nRot);
  886.     break;
  887. #ifdef BIORHYTHM
  888.   case gBiorhythm:
  889.     XChartBiorhythm();
  890.     break;
  891. #endif
  892.   }
  893.  
  894.   /* Print text showing chart information at bottom of window. */
  895.  
  896.   DrawColor(gi.kiLite);
  897.   if (fDrawText) {
  898.     if (fNoTimeOrSpace)
  899.       sprintf(sz, "(No time or space)");
  900.     else if (us.nRel == rcComposite)
  901.       sprintf(sz, "(Composite)");
  902.     else {
  903.       fT = us.fAnsiChar;
  904.       us.fAnsiChar = (!gs.fFont || (!gs.fMeta && !gs.fPS)) << 1;
  905.       i = DayOfWeek(Mon, Day, Yea);
  906.       sprintf(sz, "%c%c%c %s %s (%cT %s GMT) %s", chDay3(i),
  907.         SzDate(Mon, Day, Yea, 2), SzTim(Tim), ChDst(Dst),
  908.         SzZone(Zon), SzLocation(Lon, Lat));
  909.       us.fAnsiChar = fT;
  910.     }
  911.     DrawSz(sz, gs.xWin/2, gs.yWin-3*gi.nScaleT, dtBottom | dtErase);
  912.   }
  913.  
  914.   /* Draw a border around the chart if the mode is set and appropriate. */
  915.  
  916.   if (fDrawBorder)
  917.     DrawEdgeAll();
  918. }
  919. #endif /* GRAPH */
  920.  
  921. /* xcharts0.c */
  922.